﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using NCacheDClient.Configuration;
using System.ServiceModel;
using NCacheDClient.Exceptions;
using NCacheDClient.NCacheDServer;
using NCacheDClient.Internal.Clients;
using System.Globalization;

namespace NCacheDClient.Internal
{
    internal class ServerLookupBuilder
    {
        internal static ICacheClient[] CreateServerLookup()
        {
            var servers = GetServersFromConfig();

            // Weight of all servers
            var totalSizeAvailable = servers.Sum(s => s.MaxCacheSize);

            foreach (var server in servers)
            {
                server.Weight = (double)server.MaxCacheSize / (double)totalSizeAvailable;
            }

            return CreateServerLookupTable(servers);
        }

        private static IEnumerable<CacheServerHelper> GetServersFromConfig()
        {

            var configSection = ConfigurationManager.GetSection("NCacheD") as NCacheDConfigSection;

            var results = new List<CacheServerHelper>();

            foreach (NCacheDServerElement configServer in configSection.NCacheDServers)
            {

                ICacheClient client = ClientFactory.Create(configServer.Host, configServer.Port);
                CacheServerHelper helper = new CacheServerHelper
                {
                    Client = client
                };

                try
                {
                    helper.MaxCacheSize = client.GetSize();
                }
                catch (System.ServiceModel.CommunicationException ce)
                {
                    string errorMessage = string.Format(CultureInfo.InvariantCulture, "Error establishing connection to server '{0}' on port {1}. See inner exception for more details.", configServer.Host, configServer.Port);
                    throw new CacheServerConnectionException(errorMessage, ce);
                }
                results.Add(helper);

            }
            return results;
        }


        private static ICacheClient[] CreateServerLookupTable(IEnumerable<CacheServerHelper> servers)
        {
            int maxServers = NCacheDServerStore.WeightFactor;

            var lookupArr = new ICacheClient[maxServers];

            int index = 0;
            foreach (var server in servers)
            {
                int max = index + (int)(server.Weight * 100);
                for (int i = index; i < max; i++)
                {
                    lookupArr[i] = server.Client;
                }
                index = max;
            }

            if (index < maxServers) // uneven number, add the rest to fill up lookup table
            {
                var lastserver = lookupArr[index-1];
                for (int i = index; i < maxServers; i++)
                {
                    lookupArr[i] = lastserver;
                }
            }

            return lookupArr;
        }

    }
}
